﻿/*
COPYRIGHT (C) 2009 EPISERVER AB

THIS FILE IS PART OF REMOTE PAGE PROVIDER FOR EPISERVER CMS.
REMOTE PAGE PROVIDER FOR EPISERVER CMS IS FREE SOFTWARE: YOU CAN REDISTRIBUTE IT AND/OR MODIFY IT UNDER THE TERMS OF THE GNU LESSER GENERAL PUBLIC LICENSE VERSION v2.1 AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION.

REMOTE PAGE PROVIDER FOR EPISERVER CMS IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU LESSER GENERAL PUBLIC LICENSE FOR MORE DETAILS.
YOU SHOULD HAVE RECEIVED A COPY OF THE GNU LESSER GENERAL PUBLIC LICENSE ALONG WITH REMOTE PAGE PROVIDER FOR EPISERVER CMS]. IF NOT, SEE <HTTP://WWW.GNU.ORG/LICENSES/>.
*/
using System;
using System.Collections.Generic;
using System.Text;
using EPiServer.Web.Hosting;
using System.Web.Hosting;
using System.IO;
using EPiServer.Security;
using System.Configuration;
using EPiServer.Web;
using EPiServer.Web.Hosting.Versioning;
using System.Collections;

namespace EPiServer.Labs.RemoteProvider
{
    public class RemoteVirtualPathProviderServer
    {
        public RemoteVirtualPathProviderServer()
        {

        }

        /// <summary>
        /// Intializes the virtual path providers info.
        /// </summary>
        /// <param name="remoteVirtualPathProvidersInfo">The remote virtual path providers info.</param>
        public void IntializeVirtualPathProvidersInfo(ref RemoteVirtualPathProvidersInfo remoteVirtualPathProvidersInfo)
        {
            IDictionary<VirtualPathProvider, ProviderSettings> virtualPathProviders = VirtualPathHandler.Instance.VirtualPathProviders;
            remoteVirtualPathProvidersInfo.VirtualPathProviders = new Dictionary<string, RemoteVirtualPathProviderInfo>(virtualPathProviders.Count);

            foreach (ProviderSettings virtualPathProviderConfig in virtualPathProviders.Values)
            {
                RemoteVirtualPathProviderInfo info = new RemoteVirtualPathProviderInfo();
                info.Name = virtualPathProviderConfig.Name;
                info.ShowInFileManager = Convert.ToBoolean(virtualPathProviderConfig.Parameters.Get("showInFileManager"));
                if (virtualPathProviderConfig.Parameters.Get("showInRemoteContext") != null)
                {
                    info.ShowInFileManager = Convert.ToBoolean(virtualPathProviderConfig.Parameters.Get("showInRemoteContext"));
                }

                string virtualPath = virtualPathProviderConfig.Parameters.Get("virtualPath");
                info.VirtualPathRoot = virtualPath.StartsWith("~") ? virtualPath.Substring(1) : virtualPath; 
                info.VirtualName = virtualPathProviderConfig.Parameters.Get("virtualName");

                info.Type = virtualPathProviderConfig.Type;

                if (((VirtualPathUnifiedProvider)VirtualPathHandler.PageFolderProvider).VirtualPathRoot == info.VirtualPathRoot)
                {
                    info.IsPageFolderVirtualPathProvider = true;
                }

                info.SupportFileResolver = SupportTheInterface<IFileResolver>(info.Type);
                remoteVirtualPathProvidersInfo.VirtualPathProviders.Add(info.Name, info);
                
            }
        }

        /// <summary>
        /// Supports the interface.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        private bool SupportTheInterface<T>(string type)
        {
            return typeof(T).IsAssignableFrom(Type.GetType(type));
        }

        /// <summary>
        /// Gets the file.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        /// <param name="remoteFileInfo">The remote file info.</param>
        /// <returns></returns>
        public bool GetFile(string virtualPath, out RemoteFileInfo remoteFileInfo)
        {
            remoteFileInfo = null;
            VirtualFile virtualFile = GenericHostingEnvironment.VirtualPathProvider.GetFile(virtualPath);
            UnifiedFile  unifiedFile = virtualFile as UnifiedFile;
            if (unifiedFile != null)
            {
                remoteFileInfo = new RemoteFileInfo();
                Pack(unifiedFile, remoteFileInfo);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Gets the directory.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        /// <param name="remoteDirectoryInfo">The remote directory info.</param>
        /// <returns></returns>
        public bool GetDirectory(string virtualPath, out RemoteDirectoryInfo remoteDirectoryInfo)
        {
            remoteDirectoryInfo = new RemoteDirectoryInfo();
            VirtualDirectory virtualDirectory =  GenericHostingEnvironment.VirtualPathProvider.GetDirectory(virtualPath);
            UnifiedDirectory unifiedDirectory = virtualDirectory as UnifiedDirectory;
            if (unifiedDirectory != null)
            {
                Pack(unifiedDirectory, remoteDirectoryInfo);
                return true;
            }
            return false;
        }

        /// <summary>
        /// Files the exists.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        /// <returns></returns>
        public bool FileExists(string virtualPath)
        {
           return GenericHostingEnvironment.VirtualPathProvider.FileExists(virtualPath);
        }

        /// <summary>
        /// Directories the exists.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        /// <returns></returns>
        public bool DirectoryExists(string virtualPath)
        {
            return GenericHostingEnvironment.VirtualPathProvider.DirectoryExists(virtualPath);
        }

        /// <summary>
        /// Opens the specified virtual path.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        /// <param name="remoteFileInfo">The remote file info.</param>
        public void Open(string virtualPath, out RemoteFileInfo remoteFileInfo)
        {
            remoteFileInfo = null;
            UnifiedFile file = GetFile(virtualPath) as UnifiedFile;
            if (file != null)
            {
                remoteFileInfo = new RemoteFileInfo();
                Pack(file, remoteFileInfo);

                Stream fileStream = file.Open();
                remoteFileInfo.Content = new byte[fileStream.Length];
                if (fileStream.CanRead)
                {
                    fileStream.Read(remoteFileInfo.Content, 0, System.Convert.ToInt32(fileStream.Length));
                }
                fileStream.Close();
            }
            return;
        }

        /// <summary>
        /// Deletes the specified virtual path.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        public void Delete(string virtualPath)
        {
            UnifiedFile file = GetFile(virtualPath) as UnifiedFile;
            if (file != null)
            {
                file.Delete();
            }
        }

        /// <summary>
        /// Directorieses the specified virtual path.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        /// <returns></returns>
        public RemoteDirectoryInfo[] Directories(string virtualPath)
        {
            UnifiedDirectory dir = GetDirectory(virtualPath) as UnifiedDirectory;
            if (dir != null)
            {
                List<RemoteDirectoryInfo> remoteDirs = new List<RemoteDirectoryInfo>();
                foreach (UnifiedDirectory subDir in dir.Directories)
                {
                    RemoteDirectoryInfo remoteDir = new RemoteDirectoryInfo();
                    Pack(subDir, remoteDir);
                    remoteDirs.Add(remoteDir);
                }
                return remoteDirs.ToArray();
            }
            return null;
        }

        /// <summary>
        /// Fileses the specified virtual path.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        /// <returns></returns>
        public RemoteFileInfo[] Files(string virtualPath)
        {
            UnifiedDirectory dir = GetDirectory(virtualPath) as UnifiedDirectory;
            List<RemoteFileInfo> remoteFiles = new List<RemoteFileInfo>();

            foreach (UnifiedFile file in dir.Files)
            {
                RemoteFileInfo remoteFile = new RemoteFileInfo();
                Pack(file, remoteFile);
                remoteFiles.Add(remoteFile);
            }
            return remoteFiles.ToArray();
        }


        /// <summary>
        /// Resolves the file by GUID.
        /// </summary>
        /// <param name="guid">The GUID.</param>
        /// <returns></returns>
        public string ResolveFileByGuid(Guid guid)
        {
            PermanentFileLinkMap  pflm = PermanentLinkMapStore.Find(guid) as PermanentFileLinkMap;
            if (pflm != null  && pflm.MappedUrl != null)
            {
                return Uri.UnescapeDataString(pflm.MappedUrl.ToString());
            }
            return string.Empty;
        }

        /// <summary>
        /// Resolves the file by virtual path.
        /// </summary>
        /// <param name="virtualPath">The virtual path.</param>
        /// <param name="guid">The GUID.</param>
        /// <returns></returns>
        public string ResolveFileByVirtualPath(string virtualPath, out Guid guid)
        {

            UrlBuilder urlBuilder = new UrlBuilder(virtualPath);
            PermanentFileLinkMap pflm = PermanentLinkMapStore.Find(urlBuilder) as PermanentFileLinkMap;
            if (pflm != null)
            {
                guid = pflm.Guid;
                // ToDo: Should ask ?
                return pflm.MappedUrl.ToString();
            }
            guid = Guid.Empty;
            return null;
        }

        /// <summary>
        /// Queries the access.
        /// </summary>
        /// <param name="virtualpath">The virtualpath.</param>
        /// <returns></returns>
        public AccessLevel QueryAccess(string virtualpath)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Gets the file.
        /// </summary>
        /// <param name="virtualpath">The virtualpath.</param>
        /// <returns></returns>
        private VirtualFile GetFile(string virtualpath)
        {
            return GenericHostingEnvironment.VirtualPathProvider.GetFile(virtualpath);
        }

        /// <summary>
        /// Gets the directory.
        /// </summary>
        /// <param name="virtualpath">The virtualpath.</param>
        /// <returns></returns>
        private VirtualDirectory GetDirectory(string virtualpath)
        {
            return GenericHostingEnvironment.VirtualPathProvider.GetDirectory(virtualpath);
        }

        /// <summary>
        /// Packs the specified source dir info.
        /// </summary>
        /// <param name="sourceDirInfo">The source dir info.</param>
        /// <param name="destinationDirInfo">The destination dir info.</param>
        private void Pack(UnifiedDirectory sourceDirInfo, RemoteDirectoryInfo destinationDirInfo)
        {
            destinationDirInfo.Name = sourceDirInfo.Name;
            destinationDirInfo.IsDirectory  = sourceDirInfo.IsDirectory;
            destinationDirInfo.VirtualPath = sourceDirInfo.VirtualPath;
            destinationDirInfo.IsFirstLevel = sourceDirInfo.IsFirstLevel;
            destinationDirInfo.BypassAccessCheck = sourceDirInfo.BypassAccessCheck;
            destinationDirInfo.ProviderName = sourceDirInfo.Provider.ProviderName;
        }

        /// <summary>
        /// Packs the specified source file info.
        /// </summary>
        /// <param name="sourceFileInfo">The source file info.</param>
        /// <param name="destinationFileInfo">The destination file info.</param>
        private void Pack(UnifiedFile sourceFileInfo, RemoteFileInfo destinationFileInfo)
        {
            destinationFileInfo.Name = sourceFileInfo.Name;
            destinationFileInfo.VirtualPath = sourceFileInfo.VirtualPath;
            destinationFileInfo.Length = sourceFileInfo.Length;
            destinationFileInfo.Extension = sourceFileInfo.Extension;
            destinationFileInfo.Created = sourceFileInfo.Created;
            destinationFileInfo.Changed = sourceFileInfo.Changed;
            destinationFileInfo.ProviderName = sourceFileInfo.Provider.ProviderName;
            if (sourceFileInfo.Summary != null)
            {
                Pack(sourceFileInfo.Summary, destinationFileInfo);
            }
        }

        /// <summary>
        /// Packs the specified source file summary.
        /// </summary>
        /// <param name="sourceFileSummary">The source file summary.</param>
        /// <param name="destinationFileInfo">The destination file info.</param>
        private void Pack(IFileSummary sourceFileSummary, RemoteFileInfo destinationFileInfo)
        {
            if (sourceFileSummary != null)
            {
                destinationFileInfo.UnifiedSummaryData = new RemoteUnifiedSummaryData();
                destinationFileInfo.UnifiedSummaryData.Author = sourceFileSummary.Author;
                destinationFileInfo.UnifiedSummaryData.Category = sourceFileSummary.Category;
                destinationFileInfo.UnifiedSummaryData.Comments = sourceFileSummary.Comments;
                destinationFileInfo.UnifiedSummaryData.Keywords = sourceFileSummary.Keywords;
                destinationFileInfo.UnifiedSummaryData.Subject = sourceFileSummary.Subject;
                destinationFileInfo.UnifiedSummaryData.Title = sourceFileSummary.Title;
            }
       }


        /// <summary>
        /// Packs the specified source file summary.
        /// </summary>
        /// <param name="sourceFileSummary">The source file summary.</param>
        /// <param name="destinationFileInfo">The destination file info.</param>
        private void Pack(IUnifiedSummary sourceFileSummary, RemoteFileInfo destinationFileInfo)
        {
            if (sourceFileSummary != null)
            {
                destinationFileInfo.UnifiedSummaryData = new RemoteUnifiedSummaryData();
                destinationFileInfo.UnifiedSummaryData.Author = sourceFileSummary.Author;
                destinationFileInfo.UnifiedSummaryData.Category = sourceFileSummary.Category;
                destinationFileInfo.UnifiedSummaryData.Comments = sourceFileSummary.Comments;
                destinationFileInfo.UnifiedSummaryData.Keywords = sourceFileSummary.Keywords;
                destinationFileInfo.UnifiedSummaryData.Subject = sourceFileSummary.Subject;
                destinationFileInfo.UnifiedSummaryData.Title = sourceFileSummary.Title;
                destinationFileInfo.UnifiedSummaryData.CanPersist = sourceFileSummary.CanPersist;
                destinationFileInfo.UnifiedSummaryData.Dictionary = new Hashtable(sourceFileSummary.Dictionary);
            }
        }

    }

}